#include "MemoryMenagerGraphics.h"
#include <iostream>
#include "screen.h"
#include <fstream>
#include <math.h>
#include <conio.h>
using namespace std;

const char *S_Empty = "Empty";
const char *S_Full = "Full";
const char *S_ALL[2] = {S_Empty,S_Full}; 

const int MBLOCKS_PER_WIDTH = 20;
const int MBLOCKS_PER_HEIGTH = 3;
const int MBLOCKS_MAX_WIDTH = 140;
const int MBLOCKS_MAX_HEIGTH = 24;
const int MX_OFF = 4;
const int MY_OFF = 0;

const int PBLOCKS_PER_WIDTH = 10;
const int PBLOCKS_PER_HEIGTH = 3;
const int PBLOCKS_MAX_WIDTH = 140;
const int PBLOCKS_MAX_HEIGTH = 30;
const int PX_OFF = 4;
const int PY_OFF = 28;

const int FX_OFF = 4;
const int FY_OFF = 20;
const int FWIDTH = 100;
const int FHEIGTH = 6;

const int AnimationSteps=15;
const int AnimationDelay=50;

const int ActionX = 130;
const int ActionY = 24;

const int Action_OFFX=150;
const int Action_OFFY_Start=5;
const int Action_OFFY_End=55;


using namespace std;

MemoryMenagerGraphics::MemoryMenagerGraphics(char * FileName):
MemoryMenager(FileName) , ActionsCount(0)
{
}

MemoryMenagerGraphics::~MemoryMenagerGraphics(void)
{
}
void MemoryMenagerGraphics::Draw(int s,int stage) 
{
	if (stage==0)
	{
		DrawAction(s);
	}
	if (stage==1)
	{
		MemoryPainter = pFreeSame - Memory;
	}
	if (stage==3)
	{
		AnimateMemoryToPointer(pFreeSame - Memory);
		DrawFreePointer();
		AnimateMemoryToPointer(MemoryPainter,s);
		DrawMemoryBlock(MemoryPainter);
		DrawPointerBlock(s);
	}
	if (stage==4)
	{
		MemoryPainter = Pointer[s] - Memory;
	}
	if (stage==6)
	{
		AnimateMemoryToMemory(*pFreeSame,pFreeSame - Memory);
		DrawMemoryBlock(MemoryPainter);
		AnimateMemoryToPointer(MemoryPainter);
		DrawPointerBlock(s);
		DrawFreePointer();
	}
	if (stage==7)
	{
		DrawTextInfo();
	}

}
void MemoryMenagerGraphics::Initialize()
{
	MemoryMenager::Initialize();
	screen::MaximizeConsole();

	DrawScreen();
	
}

void MemoryMenagerGraphics::DrawBlock
(int x1,int y1,int width,int height,int ind,int value,int color,BlockStatus bs)
{
int clr;
	if (bs==BS_EMPTY)
		clr = 0x2f;
	if (bs==BS_FULL)
		clr = 0x4f;

	screen::boxex(NULL,x1,y1,x1+width,y1+height,BT_ONE,color,clr);
	screen::boxex(NULL,x1,y1+height-2,x1+width,y1+height,BT_ONE,color,0x0f);
	screen::boxex(NULL,x1,y1,x1+width,y1+2,BT_ONE,color,0x1f);


	screen::settextcolor(0x0f);
	screen::gotoxy((x1+x1+width)/2 - (int)strlen(S_ALL[bs])/2,y1+height-1);
	cout<<S_ALL[bs];

	if (value >= 0)
	{
		screen::gotoxy((x1+x1+width)/2 - 1,(y1+y1+height)/2);
		cout<<value;
	}

	if (ind >= 0)
	{
		screen::settextcolor(0x1f);
		screen::gotoxy((x1+x1+width)/2 ,y1+1);
		cout<<ind;
	}


}

void MemoryMenagerGraphics::DrawMemoryBlock(int ind)
{
BlockStatus bs;
SMALL_RECT r = getMemoryBlockRect(ind);
bs = (Memory[ind]==-1)?(BS_FULL):(BS_EMPTY);
DrawBlock(r.Left,r.Top,r.Right - r.Left,r.Bottom - r.Top,ind,Memory[ind],0x0b,bs);
}

void MemoryMenagerGraphics::DrawPointerBlock(int ind)
{
BlockStatus bs;
SMALL_RECT r = getPointerBlockRect(ind);
bs = (Pointer[ind]!=NULL)?(BS_FULL):(BS_EMPTY);
DrawBlock(r.Left,r.Top,r.Right - r.Left,r.Bottom - r.Top,ind,Pointer[ind]-Memory,0x08,bs);

}
void MemoryMenagerGraphics::DrawAction(int ind)
{
SMALL_RECT r;
int clr;


if (ind>0)
{
if (strstr(Actions[ind-1],"-")==NULL)
	clr = 0x02;
else
	clr = 0x04;

	r = getActionRect(ind-1);
	screen::boxex(NULL,r.Left-1,r.Top-1,r.Right,r.Top+1,BT_ONE,clr,0x00);

}

	r = getActionRect(ind);
	screen::boxex(NULL,r.Left-1,r.Top-1,r.Right,r.Top+1,BT_TWO,0x0e,0x00);

}
void MemoryMenagerGraphics::DrawScreen()
{
for(int i=0;i<40;i++)
	DrawMemoryBlock(i);

for(int i=0;i<30;i++)
	DrawPointerBlock(i);

	DrawFreePointer();

	DrawFileList();
	DrawTextInfo();
}

void MemoryMenagerGraphics::DrawFreePointer()
{
	DrawBlock(FX_OFF,FY_OFF,FWIDTH,FHEIGTH,-1,pFreeSame - Memory,0x02,BS_FULL);
}

SMALL_RECT MemoryMenagerGraphics::getMemoryBlockRect(int ind)
{
	SMALL_RECT r;
	int Block_Width = MBLOCKS_MAX_WIDTH / MBLOCKS_PER_WIDTH;
	int Block_Height = MBLOCKS_MAX_HEIGTH / MBLOCKS_PER_HEIGTH;
	int x = ind % MBLOCKS_PER_WIDTH;
	int y = ind / MBLOCKS_PER_WIDTH;
	int rx = x*Block_Width;
	int ry = y*(Block_Height+1);
	
	r.Left = rx + MX_OFF;
	r.Right = r.Left + Block_Width;
	r.Top = ry+MY_OFF;
	r.Bottom = r.Top + Block_Height;

	return r;
}

SMALL_RECT MemoryMenagerGraphics::getPointerBlockRect(int ind)
{
	SMALL_RECT r;
	int Block_Width = PBLOCKS_MAX_WIDTH / PBLOCKS_PER_WIDTH;
	int Block_Height = PBLOCKS_MAX_HEIGTH / PBLOCKS_PER_HEIGTH;
	int x = ind % PBLOCKS_PER_WIDTH;
	int y = ind / PBLOCKS_PER_WIDTH;
	int rx = x*Block_Width;
	int ry = y*(Block_Height+1);
	
	r.Left = rx+PX_OFF;
	r.Right = r.Left + Block_Width;
	r.Top = ry+PY_OFF;
	r.Bottom = r.Top + Block_Height;
	
	return r;
}
SMALL_RECT MemoryMenagerGraphics::getPointerRect()
{
	SMALL_RECT r;
	r.Left = FX_OFF;
	r.Right = r.Left + FWIDTH;
	r.Top = FY_OFF;
	r.Bottom = r.Top + FHEIGTH;
	return r;

}

void MemoryMenagerGraphics::AnimateMemoryToPointer(int mindex,int pindex)
{
	SMALL_RECT mr,pr;
	mr = getMemoryBlockRect(mindex);
	pr = getPointerBlockRect(pindex);

	screen::AnimateBox(mr.Left,mr.Top,mr.Right - mr.Left,mr.Bottom - mr.Top,
					   pr.Left,pr.Top,pr.Right - pr.Left,pr.Bottom - pr.Top,
					   AnimationSteps,AnimationDelay);

}
void MemoryMenagerGraphics::AnimateMemoryToPointer(int mindex)
{
	SMALL_RECT mr,pr;
	mr = getMemoryBlockRect(mindex);
	pr = getPointerRect();

	screen::AnimateBox(mr.Left,mr.Top,mr.Right - mr.Left,mr.Bottom - mr.Top,
					   pr.Left,pr.Top,pr.Right - pr.Left,pr.Bottom - pr.Top,
					   AnimationSteps,AnimationDelay);

}
void MemoryMenagerGraphics::AnimateMemoryToMemory(int fromindex,int toindex)
{
SMALL_RECT mr1,mr2;
mr1 = getMemoryBlockRect(fromindex);
mr2 = getMemoryBlockRect(toindex);
screen::AnimateBox(mr1.Left,mr1.Top,mr1.Right - mr1.Left,mr1.Bottom - mr1.Top,
				   mr2.Left,mr2.Top,mr2.Right - mr2.Left,mr2.Bottom - mr2.Top,
				   AnimationSteps,AnimationDelay);
}

void MemoryMenagerGraphics::AnimateActionToAction(int fromindex,int toindex)
{
SMALL_RECT mr1,mr2;
mr1 = getActionRect(fromindex);
mr2 = getActionRect(toindex);
screen::AnimateBox(mr1.Left-1,mr1.Top-1,mr1.Right - (mr1.Left-1),2,
				   mr2.Left-1,mr2.Top-1,mr2.Right - (mr2.Left-1),2,
				   AnimationSteps,AnimationDelay);

}

void MemoryMenagerGraphics::DrawFileList()
{
int clr;
SMALL_RECT r;
ifstream  MF;
MF.open (MemoryFileName, ios::in); 
char str[200];

screen::boxex(NULL,Action_OFFX+2,Action_OFFY_Start,Action_OFFX+6,Action_OFFY_End-2,BT_ONE,0x0d,0x00);

 while (!MF.eof())
    {
	   MF>>str;
	   Actions[ActionsCount] = new char((int)strlen(str));
	   strcpy(Actions[ActionsCount],str);
	   ActionsCount++;
	}

 MF.close();

 for(int i=0;i<ActionsCount;i++)
 {
	if (strstr(Actions[i],"-")==NULL)
		clr = 0x02;
	else
		clr = 0x04;
	r = getActionRect(i);
	screen::puttext(Actions[i],r.Left,r.Top,0x0f);
	screen::boxex(NULL,r.Left-1,r.Top-1,r.Right,r.Top+1,BT_ONE,clr,0x00);
 }

}

SMALL_RECT MemoryMenagerGraphics::getActionRect(int ind)
{
SMALL_RECT r;
int x,y;
float h;
x= Action_OFFX;
y =Action_OFFY_Start;
h = (float)(Action_OFFY_End - Action_OFFY_Start) / ActionsCount;
r.Left = x;
r.Top = y+(int)floor((float)ind*h + 0.5) ;
r.Right = r.Left + (int)strlen(Actions[ind]);

return r;
}

void MemoryMenagerGraphics::Finalize()
{
	screen::puttext("Finished ! Press Any Key To Quit...",60,19,0x1f);
	_getch();
}

void MemoryMenagerGraphics::DrawTextInfo()
{
	screen::gotoxy(110,21);
	screen::settextcolor(0x1f);
	cout<<"Block Allocations : "<<i_Alloc;

	screen::gotoxy(110,23);
	screen::settextcolor(0x1f);
	cout<<"Block Free : "<<i_Free;

	screen::gotoxy(110,25);
	screen::settextcolor(0x5f);
	cout<<"Data File Used ("<<i_Free+i_Alloc<<") of Total ("<< ActionsCount <<").";

}